<template>
  <a-modal
    v-model:open="open"
    :title="modelTitle"
    width="418px"
    centered
    :after-close="reset"
    :body-style="{ overflow: 'hidden auto', 'max-height': '600px' }"
    :mask-closable="false"
  >
    <a-form ref="formRef" :model="formState" :rules="rules" layout="vertical" class="w-352">
      <a-form-item name="name" label="标签名称">
        <a-input v-model:value="formState.name" v-trim placeholder="请输入标签名称" :maxlength="200" />
      </a-form-item>
      <a-form-item name="color" label="标签颜色">
        <color-selector v-model:selectedColor="formState.color" />
      </a-form-item>
      <a-form-item>
        <template #label>
          <div class="attr-input-label">
            <div class="label">属性</div>
            <div class="icon-add"><i class="iconfont icon-add-line" style="font-weight: 400" @click="handleAddAttr"></i></div>
          </div>
        </template>
        <a-form-item-rest>
          <div class="attr-list">
            <div v-for="(attrItem, index) in formState.propertyVoList" :key="attrItem.id" class="attr-item">
              <div class="item__header">
                <div class="w-24 h-36 fc">#{{ String(formState.propertyVoList.length - index).padStart(2, '0') }}</div>
                <a-form-item
                  class="mb-0 pl-8"
                  :name="['propertyVoList', index, 'name']"
                  :rules="[
                    { required: true, trigger: 'change', message: '请输入属性名' },
                    { validator: validateSameAttrName, trigger: 'change' },
                    { validator: validateDirName() },
                    { validator: validateBitLen(200), trigger: 'change' }
                  ]"
                >
                  <a-input v-model:value="attrItem.name" v-trim :maxlength="200" placeholder="请输入属性名" class="w-142" />
                  <a-form-item-rest>
                    <a-select
                      v-model:value="attrItem.interaction"
                      class="ml-8 no-verify"
                      style="width: 142px"
                      @change="handleInteractionChange(attrItem)"
                    >
                      <a-select-option :value="0"> 下拉框 </a-select-option>
                      <a-select-option :value="1"> 输入框 </a-select-option>
                    </a-select>
                  </a-form-item-rest>
                </a-form-item>
                <div class="attr-tool-icon ml-12 mt-6">
                  <i class="iconfont icon-subtract-line" @click="handleSubtractAttr(index)"></i>
                </div>
              </div>
              <div v-if="attrItem.interaction === 0" class="item__option-list">
                <template v-for="(option, optionIndex) in attrItem.optionList" :key="option.id">
                  <!-- 新增 -->
                  <a-form-item
                    v-if="optionIndex === attrItem.optionList.length - 1"
                    class="mb-0 pr-28"
                    :name="['propertyVoList', index, 'optionList', optionIndex, 'name']"
                    :rules="[
                      { validator: validateSameAttrName, trigger: 'change' },
                      { validator: validateDirName() },
                      { validator: validateBitLen(200), trigger: 'change' }
                    ]"
                  >
                    <a-input
                      v-model:value="option.name"
                      v-trim
                      placeholder="请新增选项"
                      class="mt-8"
                      :maxlength="200"
                      @blur="handleAddOption(option, attrItem.optionList)"
                      @pressEnter="handleAddOption(option, attrItem.optionList)"
                    />
                  </a-form-item>

                  <!-- 已有 -->
                  <a-form-item
                    v-else
                    class="w-[100%] mb-0"
                    :name="['propertyVoList', index, 'optionList', optionIndex, 'name']"
                    :rules="[
                      { required: true, trigger: 'change', message: '请输入选项' },
                      { validator: validateDirName() },
                      { validator: validateBitLen(200), trigger: 'change' }
                    ]"
                  >
                    <div class="fbc">
                      <a-input v-model:value="option.name" v-trim class="mt-8" :maxlength="200" />
                      <div class="attr-tool-icon ml-12">
                        <i
                          class="iconfont icon-indeterminate-circle-line"
                          style="font-weight: 400"
                          @click="handleSubtractOption(optionIndex, attrItem.optionList)"
                        ></i>
                      </div>
                    </div>
                  </a-form-item>
                </template>
              </div>
            </div>
          </div>
        </a-form-item-rest>
      </a-form-item>
    </a-form>
    <template #footer>
      <a-space>
        <a-button @click="open = false">取消</a-button>
        <a-button v-if="showIsContinueCreate" @mousedown="onOk(true)">继续创建</a-button>
        <a-button type="primary" @click="onOk()">确定</a-button>
      </a-space>
    </template>
  </a-modal>
</template>

<script lang="ts" setup>
  import { type FormInstance, message } from 'ant-design-vue'
  import type { Rule } from 'ant-design-vue/es/form'
  import { cloneDeep, countStrToBit, uuid } from 'g6-fn'
  import { computed, ref } from 'vue'

  import { getRandomColor } from '@/components/ColorSelector/config'
  import ColorSelector from '@/components/ColorSelector/index.vue'
  import { dmpTaskApi } from '@/services/api'
  import { regex, validateBitLen, validateDirName } from '@/utils'

  import { AttrOption, DmpTag, TagAttr } from '../../types'

  export interface Props {
    tagGroupId: string
    afterCloseFn: () => void
  }

  const props = withDefaults(defineProps<Props>(), {
    afterCloseFn: () => {}
  })

  const open = ref(false)
  const modelTitle = ref('')
  // 显示继续创建按钮
  const showIsContinueCreate = computed(() => ['创建同级标签', '创建标签'].includes(modelTitle.value))
  const formRef = ref<FormInstance>()
  const formState = ref<DmpTag>({
    id: '',
    name: '',
    color: getRandomColor(),
    pid: '',
    level: 1,
    propertyVoList: []
  })

  const rules: Record<string, Rule[]> = {
    name: [
      { required: true, trigger: 'change', message: '请输入标签名称' },
      { validator: validateDirName() },
      { validator: validateBitLen(200), trigger: 'change' }
    ]
  }

  const reset = () => {
    formRef.value?.resetFields()
    formState.value = {
      id: '',
      name: '',
      color: getRandomColor(),
      pid: '',
      level: 1,
      propertyVoList: []
    }
  }

  /**
   * @param isContinueCreate 是否继续创建
   */
  const onOk = async (isContinueCreate = false) => {
    await formRef.value?.validateFields()

    const params = cloneDeep(formState.value) as DmpTag
    params.propertyVoList.forEach(attr => {
      if (attr.interaction === 0) {
        attr.optionList = attr.optionList.filter(option => option.name !== '')
        attr.optionList.forEach(it => (it.id = ''))
      }
      attr.id = ''
    })

    const api = formState.value.id ? dmpTaskApi.tagEdit : dmpTaskApi.tagAdd
    await api({ ...params, labelGroupId: props.tagGroupId }, { isAddUid: true })
    message.success(`${formState.value.id ? '编辑' : '新增'}成功`)
    props.afterCloseFn()
    // 继续创建
    if (isContinueCreate) {
      Object.assign(formState.value, {
        id: '',
        name: '',
        color: getRandomColor()
      })

      return
    }
    open.value = false
  }

  /* 属性------------------------------------------------------------------------------------- */
  /** 校验属性名是否重复 */
  const validateSameAttrName = (rule: Rule, value: string) => {
    const hasSameName = formState.value.propertyVoList.map(item => item.name).filter(name => name === value).length > 1
    if (hasSameName) {
      return Promise.reject('属性名重复')
    } else {
      return Promise.resolve()
    }
  }

  /** 新增属性 */
  const handleAddAttr = async () => {
    const namePathList = formState.value.propertyVoList.map((_, index) => ['propertyVoList', index, 'name'])

    await formRef.value?.validate(namePathList)
    formState.value.propertyVoList.unshift({
      id: uuid(),
      name: '',
      interaction: 1,
      optionList: []
    })
  }

  /** 删除属性 */
  const handleSubtractAttr = (index: number) => {
    formState.value.propertyVoList.splice(index, 1)
  }

  /** 新增选项 */
  const handleAddOption = async (option: AttrOption, optionList: AttrOption[]) => {
    const inputValue = option.name.trim()
    if (inputValue === '') {
      return
    }
    if (!regex.dirName.test(inputValue)) {
      return
    }
    if (countStrToBit(inputValue) > 200) {
      return
    }
    option.name = ''
    optionList.splice(-1, 0, {
      id: uuid(),
      name: inputValue
    })
  }

  /** 删除选项 */
  const handleSubtractOption = (index: number, optionList: AttrOption[]) => {
    optionList.splice(index, 1)
  }

  /** 属性交互方式改变 */
  const handleInteractionChange = (attr: TagAttr) => {
    if (attr.interaction === 1) {
      attr.optionList = []
    } else {
      attr.optionList = [
        {
          id: uuid(),
          name: ''
        }
      ]
    }
  }

  /* ------------------------------------------------------------------------------------- */

  defineExpose({
    open: (form?: Partial<DmpTag>) => {
      if (form) {
        modelTitle
        Object.assign(formState.value, form)
        /* 为了布局做特殊处理 */
        formState.value.propertyVoList.forEach(attr => {
          if (attr.interaction === 0) {
            attr.optionList = attr.optionList.filter(option => option.name !== '')
            attr.optionList.push({
              id: uuid(),
              name: ''
            })
          }
        })
      }
      open.value = true
    },
    editTitle: (title: string) => {
      modelTitle.value = title
    }
  })
</script>

<style lang="less" scoped>
  .attr-input-label {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 456px;

    .icon-add {
      > i {
        font-size: 18px;
        color: rgba(16, 16, 20, 0.95);
        cursor: pointer;
        font-weight: 700;
      }
    }
  }

  .attr-list {
    display: flex;
    width: 352px;
    flex-direction: column;
    gap: 16px;

    .attr-item {
      .no-verify.ant-select {
        // border: 1px solid #e8e8eb !important;

        :deep(.ant-select-selector) {
          border: 1px solid #e8e8eb !important;
        }
      }

      .item__header {
        display: flex;
        // align-items: center;
      }

      .item__option-list {
        padding: 0 0 0 32px;
      }

      .attr-tool-icon {
        > i {
          font-size: 16px;
          color: rgba(16, 16, 20, 0.95);
          cursor: pointer;
          font-weight: 700;
        }
      }
    }
  }
</style>
